package com.kujie.access.service.impl;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kujie.access.domain.po.PropertyListManagement;
import com.kujie.access.domain.po.RegionManagement;
import com.kujie.access.domain.query.PropertyListQuery;
import com.kujie.access.domain.vo.PropertyListManageVO;
import com.kujie.access.mapper.PropertyListManagementMapper;
import com.kujie.access.mapper.RegionManagementMapper;
import com.kujie.access.service.IPropertyListService;
import com.kujie.common.core.domain.R;
import com.kujie.common.core.utils.StringUtils;
import com.kujie.common.excel.utils.ExcelUtil;
import com.kujie.common.mybatis.core.page.PageQuery;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class PropertyListManageServiceImpl implements IPropertyListService {
    private final PropertyListManagementMapper propertyListManagementMapper;
    private final RegionManagementMapper regionManagementMapper;

    @Override
    public Page<PropertyListManageVO> list(PropertyListQuery propertyListQuery, PageQuery pageQuery) {
        Page<PropertyListManageVO> result = pageQuery.build(new PropertyListManageVO());
        LambdaQueryWrapper<PropertyListManagement> propertyLqw = new LambdaQueryWrapper<>();
        constructPropertyQuery(propertyListQuery, propertyLqw);

        Page<PropertyListManagement> propertyListManagePage = propertyListManagementMapper.selectPage(pageQuery.build(), propertyLqw);
        if (CollectionUtils.isEmpty(propertyListManagePage.getRecords())) {
            log.info("数据为空");
            return result;
        }

        // 构造楼栋/区域查询条件
        List<String> indexCodes = propertyListManagePage.getRecords().stream().map(PropertyListManagement::getIndexCode).toList();
        LambdaQueryWrapper<RegionManagement> regionLqw = new LambdaQueryWrapper<>();
        if (StringUtils.isNotEmpty((propertyListQuery.getIndexCode()))) {
            regionLqw.like(StringUtils.isNotEmpty(propertyListQuery.getIndexCode()), RegionManagement::getIndexCode, propertyListQuery.getIndexCode());
        } else {
            regionLqw.in(RegionManagement::getIndexCode, indexCodes);
        }

        // 查询楼栋/区域数据
        Map<String, RegionManagement> regionUuidToRegionManagement = regionManagementMapper.selectList(regionLqw).stream().collect(Collectors.toMap(RegionManagement::getIndexCode, Function.identity()));
        List<PropertyListManageVO> voList = propertyListManagePage.getRecords().stream().map(e -> buildPropertyManageVO(e, regionUuidToRegionManagement)).toList();

        if (StringUtils.isNotEmpty(propertyListQuery.getAreaMin())) {
            voList = voList.stream().filter(e -> {
                return Double.parseDouble(e.getArea()) >= Double.parseDouble(propertyListQuery.getAreaMin()) && Double.parseDouble(e.getArea()) <= Double.parseDouble(propertyListQuery.getAreaMax());
            }).collect(Collectors.toList());
        }

        result.setTotal(propertyListManagePage.getTotal());
        result.setRecords(voList);
        return result;
    }

    @Override
    public PropertyListManageVO detail(Long id) {
        PropertyListManageVO propertyListManageVO = propertyListManagementMapper.selectVoById(id);

        LambdaQueryWrapper<RegionManagement> regionManagementLambdaQueryWrapper = new LambdaQueryWrapper<>();
        constructRegionManagementQueryWrapper(regionManagementLambdaQueryWrapper, propertyListManageVO);
        RegionManagement regionManagement = regionManagementMapper.selectOne(regionManagementLambdaQueryWrapper);

        // 拼接数据
        propertyListManageVO.setBelongArea(regionManagement.getName());
        return propertyListManageVO;
    }

    private static void constructRegionManagementQueryWrapper(LambdaQueryWrapper<RegionManagement> regionManagementLambdaQueryWrapper, PropertyListManageVO propertyListManageVO) {
        regionManagementLambdaQueryWrapper.eq(StringUtils.isNotEmpty(propertyListManageVO.getIndexCode()), RegionManagement::getIndexCode, propertyListManageVO.getIndexCode());
    }

    @Override
    public int deleteByIds(List<Long> ids) {
        if (ids == null) {
            return 0;
        }

        return propertyListManagementMapper.deleteByIds(ids);
    }

    @Override
    public boolean insert(PropertyListManagement propertyListManage) {
        PropertyListManagement propertyListManagement = propertyListManagementMapper.selectOne(new LambdaQueryWrapper<PropertyListManagement>()
            .eq(PropertyListManagement::getIndexCode, propertyListManage.getIndexCode())
            .eq(PropertyListManagement::getRoomNumber, propertyListManage.getRoomNumber()));

        if (propertyListManagement != null) {
            propertyListManage.setId(propertyListManagement.getId());
        }
        propertyListManage.setPropertyUUID(IdUtil.randomUUID());
        return propertyListManagementMapper.insertOrUpdate(propertyListManage);
    }

    @Override
    public List<PropertyListManageVO> batchExport(PropertyListQuery propertyListQuery, HttpServletResponse response) {
        List<PropertyListManagement> propertyListManagements;
        if (!propertyListQuery.getIsAll()) {
            propertyListManagements = propertyListManagementMapper.selectByIds(propertyListQuery.getIds());
        } else {
            LambdaQueryWrapper<PropertyListManagement> propertyListManagementLambdaQueryWrapper = new LambdaQueryWrapper<>();
            constructPropertyQuery(propertyListQuery, propertyListManagementLambdaQueryWrapper);
            propertyListManagements = propertyListManagementMapper.selectList(propertyListManagementLambdaQueryWrapper);
        }

        // 查询楼栋/区域数据
        Map<String, RegionManagement> indexCodeToRegionManagement = regionManagementMapper.selectList().stream().collect(Collectors.toMap(RegionManagement::getIndexCode, Function.identity()));
        return propertyListManagements.stream().map(e -> buildPropertyManageVO(e, indexCodeToRegionManagement)).toList();
    }

    @Override
    public R<?> batchImport(MultipartFile file) throws Exception {
        List<PropertyListManageVO> propertyListManageVOS = ExcelUtil.importExcel(file.getInputStream(), PropertyListManageVO.class);
        if (CollectionUtils.isEmpty(propertyListManageVOS)) {
            log.error("数据为空");
            return R.fail("导入失败，数据为空");
        }

        // 判断是否存在不存在的区域数据
        List<RegionManagement> regionManagementList = regionManagementMapper.selectList();
        Map<String, RegionManagement> regionNameMap = regionManagementList.stream().collect(Collectors.toMap(RegionManagement::getName, Function.identity()));
        List<PropertyListManageVO> notBelongList = propertyListManageVOS.stream().filter(e -> !regionNameMap.containsKey(e.getBelongArea())).toList();
        if (!notBelongList.isEmpty()) {
            String errorMsg = notBelongList.stream().map(PropertyListManageVO::getBelongArea).collect(Collectors.joining(","));
            log.error("如下区域数据不存在, {}", errorMsg);
            return R.fail("导入失败，如下区域数据不存在" + "[" + errorMsg + "]");
        }


        // 构造区域查询条件
        LambdaQueryWrapper<RegionManagement> regionManagementLambdaQueryWrapper = new LambdaQueryWrapper<>();
        regionManagementLambdaQueryWrapper.in(RegionManagement::getName, propertyListManageVOS.stream().map(PropertyListManageVO::getBelongArea).toList());

        // 获取导入文件中所有区域code
        List<RegionManagement> regionManagements = regionManagementMapper.selectList(regionManagementLambdaQueryWrapper);
        List<String> indexCodeList = regionManagements.stream().map(RegionManagement::getIndexCode).toList();
        Map<String, String> nameToIndexCode = regionManagements.stream().collect(Collectors.toMap(RegionManagement::getName, RegionManagement::getIndexCode));


        // 查询所有区域code对应的房源信息
        LambdaQueryWrapper<PropertyListManagement> propertyListManagementLambdaQueryWrapper = new LambdaQueryWrapper<>();
        propertyListManagementLambdaQueryWrapper.in(PropertyListManagement::getIndexCode, indexCodeList);
        List<PropertyListManagement> propertyListManagementsBelongs = propertyListManagementMapper.selectList(propertyListManagementLambdaQueryWrapper);

        // 获取更新数据列表
        List<PropertyListManagement> updateList = propertyListManageVOS.stream()
            .filter(propertyListManageVO -> {
                // 检查是否有匹配项
                return propertyListManagementsBelongs.stream()
                    .anyMatch(item ->
                        nameToIndexCode.get(propertyListManageVO.getBelongArea()).equals(item.getIndexCode()) &&
                            propertyListManageVO.getRoomNumber().equals(item.getRoomNumber()));
            })
            .map(propertyListManageVO -> {
                // 找到匹配项后设置 id 并构建对象
                Optional<PropertyListManagement> match = propertyListManagementsBelongs.stream()
                    .filter(item ->
                        nameToIndexCode.get(propertyListManageVO.getBelongArea()).equals(item.getIndexCode()) &&
                            propertyListManageVO.getRoomNumber().equals(item.getRoomNumber()))
                    .findFirst();

                match.ifPresent(matched -> propertyListManageVO.setId(matched.getId()));

                propertyListManageVO.setIsProcessed(true);

                PropertyListManagement propertyListManagement = buildPropertyManagement(propertyListManageVO, nameToIndexCode);
                propertyListManagement.setId(propertyListManageVO.getId());
                return propertyListManagement;
            })
            .collect(Collectors.toList());


        // 获取新增数据列表
        List<PropertyListManagement> insertList = propertyListManageVOS.stream().filter(e -> !e.getIsProcessed()).map(e -> buildPropertyManagement(e, nameToIndexCode)).toList();

        propertyListManagementMapper.insertBatch(insertList);
        propertyListManagementMapper.updateById(updateList);
        return R.ok();
    }

    private PropertyListManagement buildPropertyManagement(PropertyListManageVO propertyListManageVO, Map<String, String> nameToIndexCode) {
        return new PropertyListManagement(propertyListManageVO, nameToIndexCode);
    }

    private static PropertyListManageVO buildPropertyManageVO(PropertyListManagement po, Map<String, RegionManagement> regionUuidToRegionManagement) {
        return new PropertyListManageVO(po.getId(), po.getIndexCode(), po.getRoomNumber(), po.getArea(), po.getLeaseType(), po.getPurpose(), po.getSupportFacilities(), po.getRent(), po.getPrice(), po.getFloorPlan(), regionUuidToRegionManagement);
    }

    private static void constructPropertyQuery(PropertyListQuery propertyListQuery, LambdaQueryWrapper<PropertyListManagement> lqw) {
        lqw.like(StringUtils.isNotEmpty(propertyListQuery.getRoomNumber()), PropertyListManagement::getRoomNumber, propertyListQuery.getRoomNumber());
        lqw.ge(StringUtils.isNotEmpty(propertyListQuery.getAreaMin()), PropertyListManagement::getArea, propertyListQuery.getAreaMin());
        lqw.le(StringUtils.isNotEmpty(propertyListQuery.getAreaMax()), PropertyListManagement::getArea, propertyListQuery.getAreaMax());
        lqw.eq(StringUtils.isNotEmpty(propertyListQuery.getPurpose()), PropertyListManagement::getPurpose, propertyListQuery.getPurpose());
        lqw.eq(StringUtils.isNotEmpty(propertyListQuery.getLeaseType()), PropertyListManagement::getLeaseType, propertyListQuery.getLeaseType());
        lqw.like(StringUtils.isNotEmpty(propertyListQuery.getIndexCode()), PropertyListManagement::getIndexCode, propertyListQuery.getIndexCode());
    }
}
